package com.yanfan.energy.service.impl;

import com.yanfan.common.exception.base.BaseException;
import com.yanfan.common.utils.SecurityUtils;
import com.yanfan.energy.domain.*;
import com.yanfan.energy.mapper.SaveMoneyStandardDao;
import com.yanfan.energy.service.SaveMoneyStandardService;
import com.yanfan.energy.util.DateUtils;
import com.yanfan.energy.util.DoubleOperation;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * (SaveMoneyStandard)表服务实现类
 *
 * @author makejava
 * @since 2023-05-08 16:48:44
 */
@Service("saveMoneyStandardService")
@Transactional(rollbackFor = Exception.class)
public class SaveMoneyStandardServiceImpl implements SaveMoneyStandardService {
    @Resource
    private SaveMoneyStandardDao saveMoneyStandardDao;

    /**
     * 获取两个日期之间的所有月份 (年月)
     *
     * @param startTime
     * @return：list
     */
    public static List<DateInfo> getMonthBetweenDate(String startTime, String endTime) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
        // 声明保存日期集合
        List<DateInfo> list = new ArrayList<>();
        try {
            // 转化成日期类型
            Date startDate = sdf.parse(startTime);
            Date endDate = sdf.parse(endTime);
            //用Calendar 进行日期比较判断
            Calendar calendar = Calendar.getInstance();
            while (startDate.getTime() <= endDate.getTime()) {
                // 设置日期
                calendar.setTime(startDate);
                // 把日期添加到集合 (封装方法)
                DateInfo dateInfo = new DateInfo();
                dateInfo.setDate(startDate);
                dateInfo.setNumber(calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
                list.add(dateInfo);

                //把月数增加 1
                calendar.add(Calendar.MONTH, 1);
                // 获取增加后的日期
                startDate = calendar.getTime();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return list;
    }

    /**
     * 将传入的日期的年月得到一个值
     *
     * @param date 日期
     * @return 获取一个唯一的年月数值
     */
    public static int getYearMonth(Date date) {
        //传入日期
        Calendar calder = Calendar.getInstance();
        calder.setTime(date);//设置时间
        int year = calder.get(Calendar.YEAR);//获取年份
        int month = calder.get(Calendar.MONTH);//获取月份
        //返回年份乘以100加上月份的值，因为月份最多2位数，
        // 所以年份乘以100可以获取一个唯一的年月数值
        return year * 100 + month;
    }

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Override
    public SaveMoneyStandard queryById(Long id) {
        return this.saveMoneyStandardDao.queryById(id);
    }

    /**
     * 分页查询
     *
     * @param saveMoneyStandard 筛选条件
     * @return 查询结果
     */
    @Override
    public List<SaveMoneyStandard> queryList(SaveMoneyStandard saveMoneyStandard) {
        return this.saveMoneyStandardDao.queryAll(saveMoneyStandard);
    }

    /**
     * 新增数据
     *
     * @param saveMoneyStandard 实例对象
     * @return 实例对象
     */
    @Override
    public SaveMoneyStandard insert(SaveMoneyStandard saveMoneyStandard) {
        this.saveMoneyStandardDao.insert(saveMoneyStandard);
        return saveMoneyStandard;
    }

    /**
     * 修改数据
     *
     * @param saveMoneyStandard 实例对象
     * @return 实例对象
     */
    @Override
    public SaveMoneyStandard update(SaveMoneyStandard saveMoneyStandard) {
        this.saveMoneyStandardDao.update(saveMoneyStandard);
        return this.queryById(saveMoneyStandard.getId());
    }

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    @Override
    public boolean deleteById(Long id) {
        return this.saveMoneyStandardDao.deleteById(id) > 0;
    }

    /**
     * 初始化设备标准
     * 初始化数据---- 指定日期 到当前月的所有省钱记录
     *
     * @param startTime yyyy-MM  开始初始化的月份
     * @param endTime   yyyy-MM  结束初始化的月份
     */
    @Override
    public void saveMoneyInit(String startTime, String endTime, int purchaseSign, String groupByStr) {
        // 查询日志表所有的数据

        // 查询设备   groupByStr  = 0  ,  groupByStr 为 device_id
        // 查询设备   groupByStr  = 1  ,  groupByStr 为 workshop_id
        List<SaveMoneyStandard> saveMoneyLogs = saveMoneyStandardDao.querySaveMoneyLog(purchaseSign, groupByStr);
        if (CollectionUtils.isEmpty(saveMoneyLogs)) {
            return;
        }
        List<SaveMoneyStandard> saveMoneyListToSaveDatabase = new ArrayList<>(); // 初始化存入数据库的数据
        // 要初始化的日期list
        List<DateInfo> dateList = getMonthBetweenDate(startTime, endTime);
        // 把List 转Map
        Map<String, ArrayList<SaveMoneyStandard>> saveMoneyStandardMap = saveMoneyStandardListToMap(saveMoneyLogs, purchaseSign);
        // 遍历所有 type + 设备ID  下的设置数据
        for (String typeDeviceKey : saveMoneyStandardMap.keySet()) {
            getSaveMoneyList(saveMoneyListToSaveDatabase, dateList, saveMoneyStandardMap.get(typeDeviceKey));
        }
        // 初始化存入数据
        saveMoneyStandardDao.insertBatch(saveMoneyListToSaveDatabase);
    }

    /**
     * 把List 转成Map  key 为 能源类型+ 车间ID
     *
     * @param saveMoneyLogs 数据库log内的数据
     * @return
     */
    private Map<String, ArrayList<SaveMoneyStandard>> saveMoneyStandardListToMap(List<SaveMoneyStandard> saveMoneyLogs, int purchaseSign) {
        Map<String, ArrayList<SaveMoneyStandard>> saveMoneyStandardMap = new LinkedHashMap<>(); // 用来处理数据 ,key为 省钱类型+设备ID
        for (SaveMoneyStandard saveMoneyLog : saveMoneyLogs) {
            String key;
            if (purchaseSign == 1) {
                key = "" + saveMoneyLog.getType() + "-" + saveMoneyLog.getWorkshopId();
            } else {
                key = "" + saveMoneyLog.getType() + "-" + saveMoneyLog.getDeviceId();
            }
            ArrayList<SaveMoneyStandard> saveMoneyStandardList;
            if (saveMoneyStandardMap.containsKey(key)) {
                saveMoneyStandardList = saveMoneyStandardMap.get(key);
            } else {
                saveMoneyStandardList = new ArrayList<>();
            }
            saveMoneyStandardList.add(saveMoneyLog);
            saveMoneyStandardMap.put(key, saveMoneyStandardList);
        }
        return saveMoneyStandardMap;
    }

    /**
     * 省钱管理标准配置 定时器 （每个月跑一次）
     */
    @Override
    public void saveMoneyTimer(int purchaseSign, String groupByStr) {
        // 获取到 每种类型
        List<SaveMoneyStandard> saveMoneyLogs = saveMoneyStandardDao.querySaveMoneyLog(purchaseSign, groupByStr);
        if (CollectionUtils.isEmpty(saveMoneyLogs)) {
            return;
        }
        List<SaveMoneyStandard> saveMoneyListToSaveDatabase = new ArrayList<>(); // 初始化存入数据库的数据

        // 要初始化的日期list
        List<DateInfo> dateList = new ArrayList<>();
        DateInfo dateInfo = new DateInfo();
        dateInfo.setNumber(DateUtils.numberOfDays(new Date(), 0));
        dateInfo.setDate(new Date());
        dateList.add(dateInfo);

        // 把List 转Map
        Map<String, ArrayList<SaveMoneyStandard>> saveMoneyStandardMap = saveMoneyStandardListToMap(saveMoneyLogs, purchaseSign);
        // 遍历所有 type + 设备ID  下的设置数据
        for (String typeDeviceKey : saveMoneyStandardMap.keySet()) {
            getSaveMoneyList(saveMoneyListToSaveDatabase, dateList, saveMoneyStandardMap.get(typeDeviceKey));
        }
        // 初始化存入数据
        saveMoneyStandardDao.insertBatch(saveMoneyListToSaveDatabase);

    }

    /**
     * 采购标准列表查询接口
     *
     * @param saveMoneyStandard
     * @return
     */
    @Override
    public List<SaveMoneyStandard> saveMoneyStandardDeviceList(SaveMoneyStandard saveMoneyStandard) {
        return saveMoneyStandardDao.saveMoneyStandardDeviceList(saveMoneyStandard);
    }

    /**
     * 申请管理设备编辑接口
     *
     * @param saveMoneyStandardInfo
     * @return
     */
    @Override
    public SaveMoneyStandardInfo saveMoneyStandardDeviceEdit(SaveMoneyStandardInfo saveMoneyStandardInfo) {
        if (saveMoneyStandardInfo.getPurchaseSign().equals(1) && saveMoneyStandardInfo.getWorkshopId() == null) {
            throw new BaseException("采购标准类型 车间id不能为空");
        }
        if (saveMoneyStandardInfo.getPurchaseSign().equals(0) && saveMoneyStandardInfo.getDeviceId() == null) {
            throw new BaseException("设备标准类型 设备id不能为空");
        }
        // 费用标准详情信息List不能为空
        if (CollectionUtils.isEmpty(saveMoneyStandardInfo.getCostList())) {
            throw new BaseException("费用标准详情信息List不能为空   costList");
        }

        Integer numberOfDays = DateUtils.numberOfDays(new Date(), 0); // 本月的天数

        for (SaveMoneyStandard saveMoneyStandard : saveMoneyStandardInfo.getCostList()) {
            if (saveMoneyStandard.getType() == null) {
                throw new BaseException("费用类型不能为空   type");
            }
            //标准日期维度（1 日 2 月）
            if (saveMoneyStandard.getDateType() == null) {
                throw new BaseException(" costList 列表实体对象 dateType 标准日期维度（1 日 2 月）");
            }
            saveMoneyStandard.setWorkshopId(saveMoneyStandardInfo.getWorkshopId());// 设置车间
            saveMoneyStandard.setPurchaseSign(saveMoneyStandardInfo.getPurchaseSign()); // 设置 采购设备标识类型 1为采购 0 为设备
            saveMoneyStandard.setDeviceId(saveMoneyStandardInfo.getDeviceId()); // 设置设备id
            saveMoneyStandard.setTakeEffect(new Date());
            saveMoneyStandard.setCreateDate(new Date());
            saveMoneyStandard.setCreateBy(SecurityUtils.getUserId());
            if (saveMoneyStandard.getDateType().equals(1)) {
                saveMoneyStandard.setMonth(DoubleOperation.mul(saveMoneyStandard.getDay(), (double) numberOfDays));
            } else {
                saveMoneyStandard.setDay(DoubleOperation.divideNoRound(saveMoneyStandard.getMonth(), (double) numberOfDays));
            }
        }

        String deviceOrWorkshop;
        Integer deviceOrWorkshopValue;
        if (saveMoneyStandardInfo.getPurchaseSign().equals(1)) {
            // 清除之前的数据
            deviceOrWorkshop = "workshop_id";
            deviceOrWorkshopValue = saveMoneyStandardInfo.getWorkshopId();
        } else {
            // 清除之前的数据
            deviceOrWorkshop = "device_id";
            deviceOrWorkshopValue = saveMoneyStandardInfo.getDeviceId();
        }
        // 删除本月的 标准数据
        saveMoneyStandardDao.clearSaveMoneyDirtyData(saveMoneyStandardInfo.getCostList(), saveMoneyStandardInfo.getPurchaseSign(), deviceOrWorkshop, deviceOrWorkshopValue);
        // 加入 新的数据  并记录日志
        saveMoneyStandardDao.insertBatch(saveMoneyStandardInfo.getCostList());// 加入数据
        saveMoneyStandardDao.recordLog(saveMoneyStandardInfo.getCostList());// 记录日志
        return saveMoneyStandardInfo;
    }

    /**
     * 采购标准列表查询接口
     *
     * @param saveMoneyStandard
     * @return
     */
    @Override
    public List<SaveMoneyStandard> saveMoneyStandardPurchaseList(SaveMoneyStandard saveMoneyStandard) {
        saveMoneyStandard.setPageNum(null);
        saveMoneyStandard.setPageSize(null);
        return saveMoneyStandardDao.saveMoneyStandardPurchaseList(saveMoneyStandard);
    }

    @Override
    public SaveMoneyStandardInfo saveMoneyStandardDeviceDetail(SaveMoneyStandardInfo saveMoneyStandardInfo) {
        if (saveMoneyStandardInfo.getPurchaseSign().equals(1) && saveMoneyStandardInfo.getWorkshopId() == null) {
            throw new BaseException("采购标准类型 车间id不能为空");
        }
        if (saveMoneyStandardInfo.getPurchaseSign().equals(2) && saveMoneyStandardInfo.getDeviceId() == null) {
            throw new BaseException("设备标准类型 设备id不能为空");
        }
        SaveMoneyStandardInfo resultInfo = saveMoneyStandardDao.saveMoneyStandardDeviceDetail(saveMoneyStandardInfo);
        if (resultInfo == null || CollectionUtils.isEmpty(resultInfo.getCostList())) {
            return resultInfo;
        }
        List<String> costTypeList = new ArrayList<>();
        for (SaveMoneyStandard saveMoneyStandard : resultInfo.getCostList()) {
            costTypeList.add(saveMoneyStandard.getType());
        }
        resultInfo.setCostType(costTypeList);
        return resultInfo;
    }

    /**
     * 设备、能耗标准 下面的列表
     *
     * @param saveMoneyQueryByArea
     * @return
     */
    @Override
    public List<SaveMoneyQueryByArea> saveMoneyQueryByArea(SaveMoneyQueryByArea saveMoneyQueryByArea) {
        // 查询数据库
        List<SaveMoneyStandard> saveMoneyStandards = saveMoneyStandardDao.querySaveMoneyByArea(saveMoneyQueryByArea);
        // 初始化数据 （默认数据为0）
        List<SaveMoneyQueryByArea> resultList = new ArrayList<>();
        SaveMoneyQueryByArea dayData = new SaveMoneyQueryByArea();
        dayData.setDateType(1);
        SaveMoneyQueryByArea monthData = new SaveMoneyQueryByArea();
        monthData.setDateType(2);
        resultList.add(dayData);
        resultList.add(monthData);

        if (CollectionUtils.isEmpty(saveMoneyStandards)) {
            return resultList;
        }

        /****
         *
         数据库查出来的数据如下
         type day    month      purchase_sign
         1	 30.8	 955  	    0
         2	 505  	 15655	    0
         3	 58	     1798  	    0
         1	 5	     155	    1
         2	 20      620	    1
         需要组装成
         day    水    电  气   采购
         month  水    电  气   采购
         *
         */

        // 数据库数不为空，遍历数据 组装返回数据
        for (SaveMoneyStandard saveMoneyStandard : saveMoneyStandards) {
            if (saveMoneyStandard.getPurchaseSign().equals(1)) { // 采购
                dayData.setPurchaseCost(DoubleOperation.addNonNullTrack(saveMoneyStandard.getDay(), dayData.getPurchaseCost()));
                monthData.setPurchaseCost(DoubleOperation.addNonNullTrack(saveMoneyStandard.getMonth(), monthData.getPurchaseCost()));
                continue;
            }
            if (saveMoneyStandard.getPurchaseSign().equals(0) && saveMoneyStandard.getType().equals("1")) { // 设备配置  水
                dayData.setWaterCost(DoubleOperation.addNonNullTrack(saveMoneyStandard.getDay(), dayData.getWaterCost()));
                monthData.setWaterCost(DoubleOperation.addNonNullTrack(saveMoneyStandard.getMonth(), monthData.getWaterCost()));
                continue;
            }
            if (saveMoneyStandard.getPurchaseSign().equals(0) && saveMoneyStandard.getType().equals("2")) { // 设备配置 电
                dayData.setElectricityCost(DoubleOperation.addNonNullTrack(saveMoneyStandard.getDay(), dayData.getElectricityCost()));
                monthData.setElectricityCost(DoubleOperation.addNonNullTrack(saveMoneyStandard.getMonth(), monthData.getElectricityCost()));
                continue;
            }
            if (saveMoneyStandard.getPurchaseSign().equals(0) && saveMoneyStandard.getType().equals("3")) { // 设备配置 气
                dayData.setGasCost(DoubleOperation.addNonNullTrack(saveMoneyStandard.getDay(), dayData.getGasCost()));
                monthData.setGasCost(DoubleOperation.addNonNullTrack(saveMoneyStandard.getMonth(), monthData.getGasCost()));
                continue;
            }
        }
        return resultList;
    }

    @Override
    public List<BaseDictEntity> areaList(SaveMoneyQueryByArea saveMoneyQueryByArea) {
        return saveMoneyStandardDao.areaList(saveMoneyQueryByArea);
    }

    /**
     * 获取要保存的 省钱配置List
     *
     * @param saveMoneyListToSaveDatabase
     * @param dateList
     * @param dataSourceList
     */
    private void getSaveMoneyList(List<SaveMoneyStandard> saveMoneyListToSaveDatabase, List<DateInfo> dateList, ArrayList<SaveMoneyStandard> dataSourceList) {
        // 为 （type + 设备ID ） 下 设置指定日期区间内的省钱标准数据
        for (DateInfo dateInfo : dateList) {
            SaveMoneyStandard saveMoneyStandardValid = null;

            // 找到生效的标准省钱配置
            int size = dataSourceList.size(); // 当前设备某一type下，所有有效的设备配置
            for (int i = 0; i < size; i++) { // 循环 当前设备 某一type下的所有申请配置数据
                SaveMoneyStandard saveMoneyStandard = dataSourceList.get(i);
                Date createDate = saveMoneyStandard.getCreateDate();
                int compareDateResult = compareDate(createDate, dateInfo.getDate());
                if (compareDateResult <= 0) {
                    saveMoneyStandardValid = saveMoneyStandard;
                } else if (compareDateResult > 0) {
                    // 选当前配置条件：
                    //  1. 下一个配置的年月份 大于与要配置的dateInfo 日期
                    //  2. 没有下个配置
                    if (i + 1 == size || compareDate(dataSourceList
                                                             .get(i + 1)
                                                             .getCreateDate(), dateInfo.getDate()) > 0) {
                        saveMoneyStandardValid = saveMoneyStandard;
                    }
                }
                break;
            }
            // 添加 要往数据库 添加的数据
            SaveMoneyStandard add = new SaveMoneyStandard();
            add.setDeviceId(saveMoneyStandardValid.getDeviceId());
            add.setType(saveMoneyStandardValid.getType());
            add.setDateType(saveMoneyStandardValid.getDateType());
            add.setPurchaseSign(saveMoneyStandardValid.getPurchaseSign());
            add.setWorkshopId(saveMoneyStandardValid.getWorkshopId());
            add.setCreateBy(0L);// 系统的意思
            if (saveMoneyStandardValid.getDateType().equals(1)) {
                add.setDay(saveMoneyStandardValid.getDay());
                add.setMonth(DoubleOperation.mul(saveMoneyStandardValid.getDay(), (double) dateInfo.getNumber()));
            } else {
                add.setMonth(saveMoneyStandardValid.getMonth());
                add.setDay(DoubleOperation.divideNoRound(saveMoneyStandardValid.getMonth(), (double) dateInfo.getNumber()));
            }
            add.setCreateDate(new Date());
            add.setTakeEffect(dateInfo.getDate());
            // 添加数据
            saveMoneyListToSaveDatabase.add(add);
        }
    }

    /**
     * 比对两个日期 年月份是否相同
     *
     * @param one
     * @param two
     * @return 0  两个日期年月份相同 1 第一个日期比第二个日期晚 ； -1 第一个日期比第二个日期早
     */
    public int compareDate(Date one, Date two) {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM");
        int dateOne = getYearMonth(one);
        int dateTwo = getYearMonth(two);
        if (dateOne == dateTwo) {
            // dateOne dateTwo 相同年月份
            return 0;
        } else if (dateOne > dateTwo) {
            //dateOne比dateTwo晚
            return 1;
        } else {
            //dateOne比dateTwo早
            return -1;
        }
    }
}
